home *** CD-ROM | disk | FTP | other *** search
/ Hot Super Models / Hot Super Models.iso / unix / x11 / xv200.tar / xv-2.00 / unsupt / VMS / ARGPROC.C next >
C/C++ Source or Header  |  1992-01-01  |  13KB  |  542 lines

  1. /*
  2.  * @(#)argproc.c 1.0 89/02/01        Mark Pizzolato (mark@infopiz.uucp)
  3.  */
  4.  
  5. #ifndef lint
  6. char argproc_version[] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
  7. #endif
  8.  
  9. #include "includes.h"        /* System include files, system dependent */
  10.  
  11.  
  12. /*
  13.  * getredirection() is intended to aid in porting C programs
  14.  * to VMS (Vax-11 C) which does not support '>' and '<'
  15.  * I/O redirection, along with a command line pipe mechanism
  16.  * using the '|' AND background command execution '&'.
  17.  * The piping mechanism will probably work with almost any 'filter' type
  18.  * of program.  With suitable modification, it may useful for other
  19.  * portability problems as well.
  20.  *
  21.  * Author:  Mark Pizzolato    mark@infopiz.UUCP
  22.  */
  23. struct list_item
  24.     {
  25.     struct list_item *next;
  26.     char *value;
  27.     };
  28.  
  29. int
  30. getredirection(ac, av)
  31. int        *ac;
  32. char        ***av;
  33. /*
  34.  * Process vms redirection arg's.  Exit if any error is seen.
  35.  * If getredirection() processes an argument, it is erased
  36.  * from the vector.  getredirection() returns a new argc and argv value.
  37.  * In the event that a background command is requested (by a trailing "&"),
  38.  * this routine creates a background subprocess, and simply exits the program.
  39.  *
  40.  * Warning: do not try to simplify the code for vms.  The code
  41.  * presupposes that getredirection() is called before any data is
  42.  * read from stdin or written to stdout.
  43.  *
  44.  * Normal usage is as follows:
  45.  *
  46.  *    main(argc, argv)
  47.  *    int        argc;
  48.  *        char        *argv[];
  49.  *    {
  50.  *        getredirection(&argc, &argv);
  51.  *    }
  52.  */
  53. {
  54.     int            argc = *ac;    /* Argument Count      */
  55.     char        **argv = *av;    /* Argument Vector      */
  56.     char        *ap;           /* Argument pointer      */
  57.     int                   j;        /* argv[] index          */
  58.     extern int        errno;        /* Last vms i/o error       */
  59.     int            item_count = 0;    /* Count of Items in List */
  60.     struct list_item     *list_head = 0;    /* First Item in List        */
  61.     struct list_item    *list_tail;    /* Last Item in List        */
  62.     char         *in = NULL;    /* Input File Name        */
  63.     char         *out = NULL;    /* Output File Name        */
  64.     char         *outmode = "w";    /* Mode to Open Output File */
  65.     int            cmargc = 0;        /* Piped Command Arg Count  */
  66.     char        **cmargv = NULL;/* Piped Command Arg Vector */
  67.     stat_t        statbuf;    /* fstat buffer            */
  68.  
  69.     /*
  70.      * First handle the case where the last thing on the line ends with
  71.      * a '&'.  This indicates the desire for the command to be run in a
  72.      * subprocess, so we satisfy that desire.
  73.      */
  74.     ap = argv[argc-1];
  75.     if (0 == strcmp("&", ap))
  76.     exit(background_process(--argc, argv));
  77.     if ('&' == ap[strlen(ap)-1])
  78.     {
  79.     ap[strlen(ap)-1] = '\0';
  80.     exit(background_process(argc, argv));
  81.     }
  82.     /*
  83.      * Now we handle the general redirection cases that involve '>', '>>',
  84.      * '<', and pipes '|'.
  85.      */
  86.     for (j = 0; j < argc; ++j)
  87.     {
  88.     if (0 == strcmp("<", argv[j]))
  89.         {
  90.         if (j+1 >= argc)
  91.         {
  92.         errno = EINVAL;
  93.         perror("No input file");
  94.         exit(EXIT_ERR);
  95.         }
  96.         in = argv[++j];
  97.         continue;
  98.         }
  99.     if ('<' == *(ap = argv[j]))
  100.         {
  101.         in = 1 + ap;
  102.         continue;
  103.         }
  104.     if (0 == strcmp(">", ap))
  105.         {
  106.         if (j+1 >= argc)
  107.         {
  108.         errno = EINVAL;
  109.         perror("No output file");
  110.         exit(EXIT_ERR);
  111.         }
  112.         out = argv[++j];
  113.         continue;
  114.         }
  115.     if ('>' == *ap)
  116.         {
  117.         if ('>' == ap[1])
  118.         {
  119.         outmode = "a";
  120.         if ('\0' == ap[2])
  121.             out = argv[++j];
  122.         else
  123.             out = 2 + ap;
  124.         }
  125.         else
  126.         out = 1 + ap;
  127.         continue;
  128.         }
  129.     if (0 == strcmp("|", argv[j]))
  130.         {
  131.         if (j+1 >= argc)
  132.         {
  133.         errno = EPIPE;
  134.         perror("No command to Pipe to");
  135.         exit(EXIT_ERR);
  136.         }
  137.         cmargc = argc-(j+1);
  138.         cmargv = &argv[j+1];
  139.         argc = j;
  140.         continue;
  141.         }
  142.     if ('|' == *(ap = argv[j]))
  143.         {
  144.         ++argv[j];
  145.         cmargc = argc-j;
  146.         cmargv = &argv[j];
  147.         argc = j;
  148.         continue;
  149.         }
  150.     expand_wild_cards(ap, &list_head, &list_tail, &item_count);
  151.     }
  152.     /*
  153.      * Allocate and fill in the new argument vector, Some Unix's terminate
  154.      * the list with an extra null pointer.
  155.      */
  156.     argv = *av = calloc(item_count+1, sizeof(char *));
  157.     for (j = 0; j < item_count; ++j, list_head = list_head->next)
  158.     argv[j] = list_head->value;
  159.     *ac = item_count;
  160.     if (cmargv != NULL)
  161.     {
  162.     char subcmd[1024];
  163.     static char *pipe_and_fork();
  164.  
  165.     if (out != NULL)
  166.         {
  167.         errno = EINVAL;
  168.         perror("Invalid '|' and '>' specified");
  169.         exit(EXIT_ERR);
  170.         }
  171.     strcpy(subcmd, cmargv[0]);
  172.     for (j = 1; j < cmargc; ++j)
  173.         {
  174.         strcat(subcmd, " \"");
  175.         strcat(subcmd, cmargv[j]);
  176.         strcat(subcmd, "\"");
  177.         }
  178.     out = pipe_and_fork(subcmd);
  179.     outmode = "wb";
  180.     }
  181.     
  182.     /* Check for input from a pipe (mailbox) */
  183.  
  184.     if(fstat(0, &statbuf) == 0){
  185.     if(strncmp(statbuf.st_dev, "MB", 2) == 0 || 
  186.         strncmp(statbuf.st_dev, "_MB", 3) == 0){
  187.  
  188.         /* Input from a pipe, reopen it in binary mode to disable    */
  189.         /* carriage control processing.                */
  190.  
  191.         if (in != NULL){
  192.         errno = EINVAL;
  193.         perror("Invalid '|' and '<' specified");
  194.         exit(EXIT_ERR);
  195.         }
  196.         freopen(statbuf.st_dev, "rb", stdin);
  197.         }
  198.     }
  199.     else {
  200.     perror("fstat failed");
  201.     exit(EXIT_ERR);
  202.     }
  203.     if ((in != NULL) && (NULL == freopen(in, "r", stdin, "mbc=32", "mbf=2")))
  204.     {
  205.     perror(in);                   /* Can't find file        */
  206.     exit(EXIT_ERR);        /* Is a fatal error        */
  207.     }
  208.     if ((out != NULL) && (NULL == freopen(out, outmode, stdout, "mbc=32", "mbf=2")))
  209.     {    
  210.     perror(ap);        /* Error, can't write or append    */
  211.     exit(EXIT_ERR);        /* Is a fatal error        */
  212.     }
  213. #ifdef DEBUG
  214.     fprintf(stderr, "Arglist:\n");
  215.     for (j = 0; j < *ac;  ++j)
  216.     fprintf(stderr, "argv[%d] = '%s'\n", j, argv[j]);
  217. #endif
  218. }
  219.  
  220. static add_item(head, tail, value, count)
  221. struct list_item **head;
  222. struct list_item **tail;
  223. char *value;
  224. int *count;
  225. {
  226.     if (*head == 0)
  227.     {
  228.     if (NULL == (*head = calloc(1, sizeof(**head))))
  229.         {
  230.         errno = ENOMEM;
  231.         perror("");
  232.         exit(EXIT_ERR);
  233.         }
  234.     *tail = *head;
  235.     }
  236.     else
  237.     if (NULL == ((*tail)->next = calloc(1, sizeof(**head))))
  238.         {
  239.         errno = ENOMEM;
  240.         perror("");
  241.         exit(EXIT_ERR);
  242.         }
  243.     else
  244.         *tail = (*tail)->next;
  245.     (*tail)->value = value;
  246.     ++(*count);
  247. }
  248.  
  249. static expand_wild_cards(item, head, tail, count)
  250. char *item;
  251. struct ltem_list **head;
  252. struct ltem_list **tail;
  253. int *count;
  254. {
  255. int expcount = 0;
  256. int context = 0;
  257. int status;
  258. int status_value;
  259. int had_version;
  260. $DESCRIPTOR(filespec, item);
  261. $DESCRIPTOR(defaultspec, "SYS$DISK:[]*.*;");
  262. $DESCRIPTOR(resultspec, "");
  263.  
  264.     if (strcspn(item, "*%") == strlen(item))
  265.     {
  266.     add_item(head, tail, item, count);
  267.     return;
  268.     }
  269.     resultspec.dsc$b_dtype = DSC$K_DTYPE_T;
  270.     resultspec.dsc$b_class = DSC$K_CLASS_D;
  271.     resultspec.dsc$a_pointer = NULL;
  272.     filespec.dsc$w_length = strlen(item);
  273.     /*
  274.      * Only return version specs, if the caller specified a version
  275.      */
  276.     had_version = strchr(item, ';');
  277.     while (1 == (1&lib$find_file(&filespec, &resultspec, &context,
  278.                      &defaultspec, 0, &status_value, &0)))
  279.     {
  280.     char *string;
  281.     char *c;
  282.  
  283.     if (NULL == (string = calloc(1, resultspec.dsc$w_length+1)))
  284.         {
  285.         errno = ENOMEM;
  286.         perror("");
  287.         exit(EXIT_ERR);
  288.         }
  289.     strncpy(string, resultspec.dsc$a_pointer, resultspec.dsc$w_length);
  290.     string[resultspec.dsc$w_length] = '\0';
  291.     if (NULL == had_version)
  292.         *((char *)strrchr(string, ';')) = '\0';
  293.     /*
  294.      * Be consistent with what the C RTL has already done to the rest of
  295.      * the argv items and lowercase all of these names.
  296.      */
  297.     for (c = string; *c; ++c)
  298.         if (isupper(*c))
  299.         *c = tolower(*c);
  300.     add_item(head, tail, string, count);
  301.     ++expcount;
  302.     }
  303.     if (expcount == 0)
  304.     add_item(head, tail, item, count);
  305.     lib$sfree1_dd(&resultspec);
  306.     lib$find_file_end(&context);
  307. }
  308.  
  309. static int child_st[2];    /* Event Flag set when child process completes    */
  310.  
  311. static short child_chan;/* I/O Channel for Pipe Mailbox            */
  312.  
  313. static exit_handler(status)
  314. int *status;
  315. {
  316. short iosb[4];
  317.  
  318.     if (0 == child_st[0])
  319.     {
  320. #ifdef DEBUG
  321.     fprintf(stderr, "Waiting for Child Process to Finnish . . .\n");
  322. #endif
  323.     fflush(stdout);        /* Have to flush pipe for binary data to    */
  324.                 /* terminate properly -- <tp@mccall.com>    */
  325.     sys$qiow(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0);
  326.     sys$dassgn(child_chan);
  327.     fclose(stdout);
  328.     sys$synch(0, child_st);
  329.     }
  330. }
  331.  
  332. #include syidef        /* System Information Definitions    */
  333.  
  334. static sig_child(chan)
  335. int chan;
  336. {
  337. #ifdef DEBUG
  338.     fprintf(stderr, "Child Completion AST\n");
  339. #endif
  340.     if (child_st[0] == 0)
  341.     child_st[0] = 1;
  342. }
  343.  
  344. static struct exit_control_block
  345.     {
  346.     struct exit_control_block *flink;
  347.     int    (*exit_routine)();
  348.     int arg_count;
  349.     int *status_address;
  350.     int exit_status;
  351.     } exit_block =
  352.     {
  353.     0,
  354.     exit_handler,
  355.     1,
  356.     &exit_block.exit_status,
  357.     0
  358.     };
  359.  
  360. static char *pipe_and_fork(cmd)
  361. char *cmd;
  362. {
  363.     $DESCRIPTOR(cmddsc, cmd);
  364.     static char mbxname[64];
  365.     $DESCRIPTOR(mbxdsc, mbxname);
  366.     short iosb[4];
  367.     int status;
  368.     int pid;
  369.     struct
  370.     {
  371.     short dna_buflen;
  372.     short dna_itmcod;
  373.     char *dna_buffer;
  374.     short *dna_retlen;
  375.     int listend;
  376.     } itmlst =
  377.     {
  378.     sizeof(mbxname),
  379.     DVI$_DEVNAM,
  380.     mbxname,
  381.     &mbxdsc.dsc$w_length,
  382.     0
  383.     };
  384.     int mbxsize;
  385.     struct
  386.     {
  387.     short mbf_buflen;
  388.     short mbf_itmcod;
  389.     int *mbf_maxbuf;
  390.     short *mbf_retlen;
  391.     int listend;
  392.     } syiitmlst =
  393.     {
  394.     sizeof(mbxsize),
  395.     SYI$_MAXBUF,
  396.     &mbxsize,
  397.     0,
  398.     0
  399.     };
  400.  
  401.     cmddsc.dsc$w_length = strlen(cmd);
  402.     /*
  403.      * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
  404.      * the size of the 'pipe' mailbox.
  405.      */
  406.     if (1 == (1&(vaxc$errno = sys$getsyiw(0, 0, 0, &syiitmlst, iosb, 0, 0, 0))))
  407.     vaxc$errno = iosb[0];
  408.     if (0 == (1&vaxc$errno))
  409.     {
  410.      errno = EVMSERR;
  411.     perror("Can't get SYSGEN parameter value for MAXBUF");
  412.     exit(EXIT_ERR);
  413.     }
  414.     if (mbxsize > 2048)
  415.     mbxsize = 2048;
  416.     if (0 == (1&(vaxc$errno = sys$crembx(0, &child_chan, mbxsize, mbxsize, 0, 0, 0))))
  417.     {
  418.     errno = EVMSERR;
  419.     perror("Can't create pipe mailbox");
  420.     exit(EXIT_ERR);
  421.     }
  422.     if (1 == (1&(vaxc$errno = sys$getdviw(0, child_chan, 0, &itmlst, iosb,
  423.                           0, 0, 0))))
  424.     vaxc$errno = iosb[0];
  425.     if (0 == (1&vaxc$errno))
  426.     {
  427.      errno = EVMSERR;
  428.     perror("Can't get pipe mailbox device name");
  429.     exit(EXIT_ERR);
  430.     }
  431.     mbxname[mbxdsc.dsc$w_length] = '\0';
  432. #ifdef DEBUG
  433.     fprintf(stderr, "Pipe Mailbox Name = '%s'\n", mbxname);
  434. #endif
  435.     if (0 == (1&(vaxc$errno = lib$spawn(&cmddsc, &mbxdsc, 0, &1,
  436.                         0, &pid, child_st, &0, sig_child,
  437.                         &child_chan))))
  438.     {
  439.     errno = EVMSERR;
  440.     perror("Can't spawn subprocess");
  441.     exit(EXIT_ERR);
  442.     }
  443. #ifdef DEBUG
  444.     fprintf(stderr, "Subprocess's Pid = %08X\n", pid);
  445. #endif
  446.     sys$dclexh(&exit_block);
  447.     return(mbxname);
  448. }
  449.  
  450. background_process(argc, argv)
  451. int argc;
  452. char **argv;
  453. {
  454. char command[2048] = "$";
  455. $DESCRIPTOR(value, command);
  456. $DESCRIPTOR(cmd, "BACKGROUND$COMMAND");
  457. $DESCRIPTOR(null, "NLA0:");
  458. int pid;
  459.  
  460.     strcat(command, argv[0]);
  461.     while (--argc)
  462.     {
  463.     strcat(command, " \"");
  464.     strcat(command, *(++argv));
  465.     strcat(command, "\"");
  466.     }
  467.     value.dsc$w_length = strlen(command);
  468.     if (0 == (1&(vaxc$errno = lib$set_symbol(&cmd, &value))))
  469.     {
  470.     errno = EVMSERR;
  471.     perror("Can't create symbol for subprocess command");
  472.     exit(EXIT_ERR);
  473.     }
  474.     if (0 == (1&(vaxc$errno = lib$spawn(&cmd, &null, 0, &17, 0, &pid))))
  475.     {
  476.     errno = EVMSERR;
  477.     perror("Can't spawn subprocess");
  478.     exit(EXIT_ERR);
  479.     }
  480. #ifdef DEBUG
  481.     fprintf(stderr, "%s\n", command);
  482. #endif
  483.     fprintf(stderr, "%08X\n", pid);
  484.     return(EXIT_OK);
  485. }
  486.  
  487. /* got this off net.sources */
  488.  
  489. #ifdef    VMS
  490. #define    index    strchr
  491. #endif    /*VMS*/
  492.  
  493. /*
  494.  * get option letter from argument vector
  495.  */
  496. int    opterr = 1,        /* useless, never set or used */
  497.     optind = 1,        /* index into parent argv vector */
  498.     optopt;            /* character checked for validity */
  499. char    *optarg;        /* argument associated with option */
  500.  
  501. #define BADCH    (int)'?'
  502. #define EMSG    ""
  503. #define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  504.         fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  505.  
  506. getopt(nargc,nargv,ostr)
  507. int    nargc;
  508. char    **nargv,
  509.     *ostr;
  510. {
  511.     static char    *place = EMSG;    /* option letter processing */
  512.     register char    *oli;        /* option letter list index */
  513.     char    *index();
  514.  
  515.     if(!*place) {            /* update scanning pointer */
  516.         if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  517.         if (*place == '-') {    /* found "--" */
  518.             ++optind;
  519.             return(EOF);
  520.         }
  521.     }                /* option letter okay? */
  522.     if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
  523.         if(!*place) ++optind;
  524.         tell(": illegal option -- ");
  525.     }
  526.     if (*++oli != ':') {        /* don't need argument */
  527.         optarg = NULL;
  528.         if (!*place) ++optind;
  529.     }
  530.     else {                /* need an argument */
  531.         if (*place) optarg = place;    /* no white space */
  532.         else if (nargc <= ++optind) {    /* no arg */
  533.             place = EMSG;
  534.             tell(": option requires an argument -- ");
  535.         }
  536.          else optarg = nargv[optind];    /* white space */
  537.         place = EMSG;
  538.         ++optind;
  539.     }
  540.     return(optopt);            /* dump back option letter */
  541. }
  542.